package fr.bugtracker.bean.security;

import java.io.IOException;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.security.core.context.SecurityContextHolder;

import fr.bugtracker.commun.enumeration.EnumCodeLogin;
import fr.bugtracker.commun.enumeration.EnumLoggerLevel;
import fr.bugtracker.commun.outils.UtilsJsf;
import fr.bugtracker.commun.outils.UtilsLogger;
import fr.bugtracker.entity.technique.Utilisateur;

/**
 * Bean pour l'authentification d'un utilisateur
 * @author lparrot
 */
@ManagedBean
@RequestScoped
public class BeanLogin {

	/**
	 * URI d'authentification.
	 */
	private static final String SPRING_SECURITY_LOGIN = "/j_spring_security_check";
	/**
	 * URI de deconnexion.
	 */
	private static final String SPRING_SECURITY_LOGOUT = "/j_spring_security_logout";
	/**
	 * URI pour le changement temporaire de compte
	 */
	private static final String SPRING_SECURITY_SWITCH_USER = "/j_spring_security_switch_user";
	/**
	 * URI pour quitter le changement temporaire de compte
	 */
	private static final String SPRING_SECURITY_EXIT_USER = "/j_spring_security_exit_user";
	/**
	 * le login entré par l'utilisateur
	 */
	@NotEmpty
	private String login;

	/**
	 * le mot de passe entré par l'utilisateur
	 */
	@NotEmpty
	private String password;

	/**
	 * Constructeur de la classe <code>BeanLogin</code>.
	 */
	public BeanLogin() {
	}

	/**
	 * Méthode d'initialisation du fr.bugtracker.bean
	 */
	public void init() {
		if (FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("code") != null) {
			EnumCodeLogin codeLogin = EnumCodeLogin.valueOf(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("code"));
			switch (codeLogin) {
			case deconnexion:
				UtilsJsf.addMessage(FacesMessage.SEVERITY_INFO, "fonctionnel.compte.erreur.deconnecte");
				break;
			case expired:
				UtilsJsf.addMessage(FacesMessage.SEVERITY_ERROR, "fonctionnel.compte.erreur.session_expire");
				break;
			default:
				break;
			}
		}
	}

	/**
	 * Dispatcher
	 * @param ctx Contextb externe.
	 * @param springAction Action
	 * @return RequestDispatcher.
	 */
	private RequestDispatcher getDispatcher(ExternalContext ctx, String springAction) {
		return ((ServletRequest) ctx.getRequest()).getRequestDispatcher(springAction);
	}

	/**
	 * Sert a forwarder.
	 * @param url url
	 * @throws ServletException exception
	 * @throws IOException ioexception.
	 */
	private void doForward(String url) throws ServletException, IOException {
		ExternalContext ctx = FacesContext.getCurrentInstance().getExternalContext();
		RequestDispatcher dispatcher = this.getDispatcher(ctx, url);
		dispatcher.forward((ServletRequest) ctx.getRequest(), (ServletResponse) ctx.getResponse());
		FacesContext.getCurrentInstance().responseComplete();
	}

	/**
	 * Méthode pour se logguer
	 * @return {@link String} null
	 * @throws IOException -
	 * @throws ServletException -
	 */
	public String doLogin() throws IOException, ServletException {
		this.doForward(SPRING_SECURITY_LOGIN);
		return null;
	}

	/**
	 * Méthode pour se déconnecter
	 * @return {@link String} null
	 * @throws ServletException -
	 * @throws IOException -
	 */
	public String logOut() throws ServletException, IOException {
		this.doForward(SPRING_SECURITY_LOGOUT);
		return null;
	}

	/**
	 * Permet de switcher d'utilisateur
	 * @param login {@link String}
	 * @return {@link String}
	 * @throws ServletException -
	 * @throws IOException -
	 */
	public String doSwitchUser(String login) throws ServletException, IOException {
		if (((Utilisateur) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getProfil().isAdministrateur()) {
			this.doForward(String.format("%s?j_username=%s", SPRING_SECURITY_SWITCH_USER, login));
			UtilsJsf.getBeanSession().setSwitched(true);
			UtilsLogger.logFonctionnel(EnumLoggerLevel.info, false, "Switch en utilisateur " + login);
		} else {
			UtilsJsf.addMessage(FacesMessage.SEVERITY_ERROR, "technique.security.switch_user_not_granted", login);
		}
		return null;
	}

	/**
	 * Permet de quitter l'utilisateur en cours
	 * @return {@link String}
	 * @throws ServletException -
	 * @throws IOException -
	 */
	public String doExitUser() throws ServletException, IOException {
		this.doForward(SPRING_SECURITY_EXIT_USER);
		UtilsJsf.getBeanSession().setSwitched(false);
		return null;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut login.</b></p>
	 * @return Retourne l'attribut login sous forme de <code>String</code>.
	 */
	public String getLogin() {
		return this.login;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut login.</b></p>
	 * @param login L'attribut login à modifier.
	 */
	public void setLogin(String login) {
		this.login = login;
	}

	/**
	 * <p><b>Accès en lecture à l'attribut password.</b></p>
	 * @return Retourne l'attribut password sous forme de <code>String</code>.
	 */
	public String getPassword() {
		return this.password;
	}

	/**
	 * <p><b>Accès en écriture à l'attribut password.</b></p>
	 * @param password L'attribut password à modifier.
	 */
	public void setPassword(String password) {
		this.password = password;
	}

}
